package funcional.atendimento;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import pessoal.Endereco;
import pessoal.cliente.ClienteFiel;
import pessoal.funcionario.Funcionario;
import suite.SuiteAbstrata;
import suite.SuiteLuxo;
import suite.SuitePresidencial;
import suite.SuiteStandard;
import suite.SuiteSuperLuxo;
import util.Conexao;
import util.ErroAcessoRepositorioException;
import funcional.atendimento.exception.AtendimentoInvalidoException;

public class RepositorioAtendimentoBDR implements IRepositorioAtendimento {

	private static final String MSG_ERRO_ACESSO_BD = "Erro de acesso ao banco de dados";
	
	private static final String INSERT_ATENDIMENTO = "INSERT INTO atend (cpf_func," +
			"id_suite,data_hora_entrada,data_hora_saida) VALUES (?,?,?,?)";
	
	private static final String INSERT_ATENDIMENTO_CLIENTE_FIEL = 
		"INSERT INTO atend_cli_fiel (cpf_cliente,id_atend) VALUES (?,?)";

	private static final String CONSULTA_LISTAR = "SELECT * FROM atend";

	private static final String DELETE_ATENDIMENTO = "DELETE FROM atend WHERE id_atend = ?";
	
	private static final String DELETE_ATENDIMENTO_CLIENTE_FIEL = "DELETE FROM atend_cli_fiel"+
	" WHERE id_atend = ?";

	private static final String UPDATE_ATENDIMENTO = "UPDATE atend SET cpf_func = ?, " +
			"id_suite = ?, data_hora_entrada = ?, data_hora_saida = ?" +
			" WHERE id_atend = ?";
	
	private static final String UPDATE_ATENDIMENTO_CLIENTE_FIEL = "UPDATE atend_cli_fiel " +
			"SET cpf_cliente = ? WHERE id_atend = ?";

	private static final String SELECT_ATENDIMENTO = "SELECT  *  FROM atend " +
			"LEFT JOIN atend_cli_fiel " +
			"ON atend.id_atend = atend_cli_fiel.id_atend " +
			"INNER JOIN suite " +
			"ON atend.id_suite = suite.id_suite " +
			"INNER JOIN func " +
			"ON atend.cpf_func=func.cpf_func " +
			"INNER JOIN pessoa " +
			"ON func.cpf_func=pessoa.cpf " +
			"WHERE id_atend = ?";

	private static final String SELECT_ATENDIMENTO_CLIENTE_FIEL = "SELECT  *  " +
			"FROM atend_cli_fiel INNER JOIN cliente " +
			"ON atend_cli_fiel.cpf_cliente = cliente.cpf_cliente " +
			"INNER JOIN pessoa " +
			"ON pessoa.cpf = cliente.cpf_cliente " +
			"WHERE id_atend = ?";
	
	private static final String SELECT_ATENDIMENTO_LISTAR = "SELECT id_atend FROM atend";
	
	private void levantaErroAcessoException(SQLException e) throws ErroAcessoRepositorioException {
		throw new ErroAcessoRepositorioException(MSG_ERRO_ACESSO_BD,
				e,
				e.getErrorCode());
	}
	
	public void atualizarAtendimento(AtendimentoAbstrato atendimento) throws ErroAcessoRepositorioException, AtendimentoInvalidoException {
		PreparedStatement pstmt = null;
		Connection con = null;
		ResultSet rs = null;
		try {
			con = Conexao.getConexao();
			pstmt = con.prepareStatement(UPDATE_ATENDIMENTO);
			pstmt.setString(1, atendimento.getFuncionario().getCpf());
			pstmt.setInt(2, atendimento.getSuite().getNumeroSuite());
			if(atendimento.getDataHoraEntrada()!=null){
				pstmt.setTimestamp(3,new Timestamp(atendimento.getDataHoraEntrada().getTime()));
			}else{
				pstmt.setTimestamp(3,null);
			}
			if(atendimento.getDataHoraSaida()!=null){
				pstmt.setTimestamp(4,new Timestamp(atendimento.getDataHoraSaida().getTime()));
			}else{
				pstmt.setTimestamp(4,null);
			}
			pstmt.setInt(5, atendimento.getNumAtendimento());
			int rows = pstmt.executeUpdate();
			if(rows == 0){
				throw new AtendimentoInvalidoException(atendimento.getNumAtendimento());
			}
			if(atendimento instanceof AtendimentoComum){
				pstmt = con.prepareStatement("DELETE FROM atend_cli_fiel WHERE id_atend = ?");
				pstmt.setInt(1, atendimento.getNumAtendimento());
				pstmt.executeUpdate();
			}
			if(atendimento instanceof AtendimentoClienteFiel){
				AtendimentoClienteFiel aux = (AtendimentoClienteFiel)atendimento;
				pstmt = con.prepareStatement("SELECT id_atend FROM atend_cli_fiel WHERE id_atend = ?");
				pstmt.setInt(1, atendimento.getNumAtendimento());
				rs = pstmt.executeQuery();
				if(!rs.next()){
					pstmt = con.prepareStatement("INSERT INTO atend_cli_fiel (id_atend,cpf_cliente) VALUES (?,?)");
					pstmt.setInt(1, atendimento.getNumAtendimento());
					pstmt.setString(2, aux.getClienteFiel().getCpf());
					pstmt.executeUpdate();
				}else{
					pstmt = con.prepareStatement(UPDATE_ATENDIMENTO_CLIENTE_FIEL);
					pstmt.setString(1, aux.getClienteFiel().getCpf());
					pstmt.setInt(2, atendimento.getNumAtendimento());
					pstmt.executeUpdate();
				}
			}
		} catch (SQLException e) {
			levantaErroAcessoException(e);
		} finally{
			Conexao.fechaRecursos(con, pstmt, rs);
		}
	}

	
	public AtendimentoAbstrato consultarAtendimento(int numAtendimento) throws ErroAcessoRepositorioException, AtendimentoInvalidoException {
		PreparedStatement pstmt = null;
		Connection con = null;
		ResultSet  rs = null;
		AtendimentoAbstrato atend = null;
		Date dataHoraIni = null;
		Date dataHoraFim = null;
		try {
			con = Conexao.getConexao();
			pstmt = con.prepareStatement(SELECT_ATENDIMENTO);
			pstmt.setInt(1, numAtendimento);
			rs = pstmt.executeQuery();
			if(rs.next()){
				String rua = rs.getString("rua");
				String numero = rs.getString("numero");
				String complemento = rs.getString("complemento");
				String bairro = rs.getString("bairro");
				String cidade = rs.getString("cidade");
				String cep = rs.getString("cep");
				String uf = rs.getString("uf");
				String cpfFunc = rs.getString("cpf_func");
				String nome = rs.getString("nome");
				String rg = rs.getString("rg");
				double salario = rs.getDouble("salario");
				Timestamp ini = rs.getTimestamp("data_hora_entrada");
				
				if(ini!=null)
					dataHoraIni = new Date(ini.getTime());
				Timestamp fim = rs.getTimestamp("data_hora_saida");
				if(fim!=null)
					dataHoraFim = new Date(fim.getTime());
				int numSuite = rs.getInt("id_suite");
				String ramal = rs.getString("ramal");
				int status = rs.getInt("status_suite");
				double precoHoraExcedente = rs.getDouble("preco_hora_excedente");
				double preco = rs.getDouble("preco");
				int tipoSuite = rs.getInt("tp_suite");
				Endereco end = new Endereco(rua,numero,complemento,bairro,cidade,cep,uf);
				Funcionario func = new Funcionario(cpfFunc,nome,rg,end,salario);
				SuiteAbstrata suite = null;
				if(tipoSuite == 1){
					suite = new SuiteStandard(numSuite,ramal,status,precoHoraExcedente,preco);
				}else if(tipoSuite == 2){
					suite = new SuiteLuxo(numSuite,ramal,status,precoHoraExcedente,preco);
				}else if(tipoSuite == 3){
					suite = new SuiteSuperLuxo(numSuite,ramal,status,precoHoraExcedente,preco);
				}else{
					suite = new SuitePresidencial(numSuite,ramal,status,precoHoraExcedente,preco);
				}
				String cpfCliente = rs.getString("cpf_cliente");
				if(cpfCliente!=null){
					pstmt = con.prepareStatement(SELECT_ATENDIMENTO_CLIENTE_FIEL);
					pstmt.setInt(1, numAtendimento);
					rs = pstmt.executeQuery();
					if(rs.next()){
						String ruaCliente = rs.getString("rua");
						String numeroCliente = rs.getString("numero");
						String complementoCliente = rs.getString("complemento");
						String bairroCliente = rs.getString("bairro");
						String cidadeCliente = rs.getString("cidade");
						String cepCliente = rs.getString("cep");
						String ufCliente = rs.getString("uf");
						String nomeCliente = rs.getString("nome");
						String rgCliente = rs.getString("rg");
						double desconto = rs.getDouble("desconto");
						Endereco endCliente = new Endereco(ruaCliente,numeroCliente,complementoCliente,bairroCliente,cidadeCliente,cepCliente,ufCliente);
						ClienteFiel cli = new ClienteFiel(cpfCliente,nomeCliente,rgCliente,endCliente,desconto);
						atend = new AtendimentoClienteFiel(numAtendimento,func,suite,dataHoraIni,dataHoraFim,cli);
					}
				}else{
					atend = new AtendimentoComum(numAtendimento,func,suite,dataHoraIni,dataHoraFim);
				}
			}else{
				throw new AtendimentoInvalidoException(numAtendimento);
			}
		} catch (SQLException e) {
			levantaErroAcessoException(e);
		} finally{
			Conexao.fechaRecursos(con, pstmt, rs);
		}
		return atend;
	}

	 
	public void excluirAtendimento(int numAtendimento) throws ErroAcessoRepositorioException, AtendimentoInvalidoException {
		PreparedStatement pstmt = null;
		Connection con = null;
		try {
			con = Conexao.getConexao();
			pstmt = con.prepareStatement(DELETE_ATENDIMENTO_CLIENTE_FIEL);
			pstmt.setInt(1, numAtendimento);
			pstmt.executeUpdate();
			
			pstmt = con.prepareStatement(DELETE_ATENDIMENTO);
			pstmt.setInt(1, numAtendimento);
			int rows = pstmt.executeUpdate();
			if(rows == 0){
				throw new AtendimentoInvalidoException(numAtendimento);
			}
		} catch (SQLException e) {
			levantaErroAcessoException(e);
		}finally{
			Conexao.fechaRecursos(con, pstmt, null);
		}
	}

	 
	public void inserirAtendimento(AtendimentoAbstrato atendimento) throws ErroAcessoRepositorioException {
		PreparedStatement pstmt = null;
		Connection con = null;
		ResultSet  rs = null;
		try {
			con = Conexao.getConexao();
			pstmt = con.prepareStatement(INSERT_ATENDIMENTO);
			pstmt.setString(1, atendimento.getFuncionario().getCpf());
			pstmt.setInt(2, atendimento.getSuite().getNumeroSuite());
			if(atendimento.getDataHoraEntrada()!=null){
				pstmt.setTimestamp(3,new Timestamp(atendimento.getDataHoraEntrada().getTime()));
			}else{
				pstmt.setTimestamp(3,null);
			}
			if(atendimento.getDataHoraSaida()!=null){
				pstmt.setTimestamp(4,new Timestamp(atendimento.getDataHoraSaida().getTime()));
			}else{
				pstmt.setTimestamp(4,null);
			}
			pstmt.executeUpdate();
			if(atendimento instanceof AtendimentoClienteFiel){
				pstmt = con.prepareStatement(CONSULTA_LISTAR);
				rs = pstmt.executeQuery();
				int i = -1;
				while(rs.next()){//Para saber qual o atend. comum equivalente a esse atend. cliente fiel
					i=rs.getInt(1);
				}
				AtendimentoClienteFiel atendAux = (AtendimentoClienteFiel) atendimento;
				pstmt = con.prepareStatement(INSERT_ATENDIMENTO_CLIENTE_FIEL);
				pstmt.setString(1, atendAux.getClienteFiel().getCpf());
				pstmt.setInt(2, i);
				pstmt.executeUpdate();
			}
		} catch (SQLException e) {
			levantaErroAcessoException(e);
		} finally{
			Conexao.fechaRecursos(con, pstmt, rs);
		}
	}

	
	 
	public List<AtendimentoAbstrato> listarAtendimentos() throws ErroAcessoRepositorioException {
		PreparedStatement pstmt = null;
		Connection con = null;
		ResultSet  rs = null;
		List<AtendimentoAbstrato> atendimentos = new ArrayList<AtendimentoAbstrato>();
		con = Conexao.getConexao();
		int numAtendimento = -1;
		try {
			pstmt = con.prepareStatement(SELECT_ATENDIMENTO_LISTAR);
			rs = pstmt.executeQuery();
			while(rs.next()){
				numAtendimento = rs.getInt(1);
				try {
					if (numAtendimento!=-1)//checa se foi achado algum atendimento antes de consultar.
						atendimentos.add(consultarAtendimento(numAtendimento));
				} catch (AtendimentoInvalidoException e) {
					e.printStackTrace();
				}
			}
		} catch (SQLException e) {
			levantaErroAcessoException(e);
		} finally{
			Conexao.fechaRecursos(con, pstmt, rs);
		}
		return atendimentos;
	}

}
